package com.hk.mini;

import com.alibaba.fastjson.JSONObject;
import com.hk.ChannelPool;
import com.hk.UObject;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;


public class MiniServerHandler  extends ChannelInboundHandlerAdapter{
    private static Logger logger = LoggerFactory.getLogger(MiniServerHandler.class);

    /**
     * 是否做CRC校验
     */
    private static final boolean IS_CHECK_CRC = true;

    /**
     * fefe0008e20202049c5d06c0
     * 命令长度最短为24（String）
     */
    private static final int MIN_CODE_LEN = 24;
    /**
     * 获得的状态码长度
     */
    private static final int STATUS_CODE_LEN = 180;
    /**
     * 心跳码
     */
    private static final String HEART_CODE = "E2";
    /**
     * 命令码
     */
    private static final String COMMAND_CODE = "EA";

    /**
     * mini主机id，每一个连接一个主机id  10进制
     */
    private Long miniId;

    private Map<String,UObject> message = new TreeMap<>();

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

        logger.info("连接进入：" + ctx.channel().remoteAddress());

        ChannelPool.miniPool.add(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;

        ctx.channel().eventLoop().execute(new Runnable() {
            @Override
            public void run() {

                //命令长度不够
                if (body.length() < MIN_CODE_LEN) {
                    logger.debug("命令长度不足" + body);
                    return;
                }

                String command = body.substring(8, 10);


                if (HEART_CODE.equalsIgnoreCase(command)) {
                    //心跳码

                    logger.debug("获得心跳码:" + body);
                    if (miniId == null) {
                        miniId = Long.valueOf(body.substring(14, 22), 16);
                    }

                    logger.debug("mini主机id:" + miniId);

                } else if (COMMAND_CODE.equalsIgnoreCase(command)) {
                    if (IS_CHECK_CRC == true) {
                        //CRC校验
                        String data = body.substring(22, body.length() - 4);
                        String crc = MBUtil.getCRC(data);

                        if (!crc.equalsIgnoreCase(body.substring(body.length() - 4))) {
                            logger.debug("CRC校验失败：" + body);
                            return;
                        }
                    }


                    if (body.length() == STATUS_CODE_LEN) {
                        //状态码

                        logger.debug("获得状态码：" + body);
                        parseStatusCommand(ctx, body);
                    } else {
                        //标签码

                        logger.debug("获得标签码：" + body);
                        parseTagCommand(ctx, body);
                    }

                } else {
                    logger.debug("未知命令：" + body);
                }

            }
        });
    }



    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        logger.info("连接断开：" + ctx.channel().remoteAddress());
        ChannelPool.miniPool.remove(ctx);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.warn("发生异常，断开连接：" + ctx.channel().remoteAddress());
        cause.printStackTrace();

        ctx.close();
    }

    /**
     * 解析状态码
     * @param ctx
     * @param body
     */
    private void parseStatusCommand(ChannelHandlerContext ctx, String body) {


        //解码
        StatusCommond statusCommond = new StatusCommond(body);


        logger.debug("解析状态码：" + statusCommond);

        int section = statusCommond.getSection();
        int uNum = statusCommond.getUNum();

        //模块节数和U位数不匹配
        if (section * 6 !=uNum){
            logger.info("模块节数和U位数不匹配："+body);
            return;
        }


        String statusCode = statusCommond.getStatus();

        for (int i = 1; i <= uNum; i++) {
            //U位码 = 主机码+模块地址+顺位
            String code = statusCommond.getMiniId()
                    + statusCommond.getModAddr()
                    + String.format("%02d", i);

            //U位状态  每2位为一个状态
            String status = statusCode.substring((i - 1) * 2, i * 2);

            UObject object = new UObject();
            object.setCode(code);
            object.setStatus(status);
            object.setMiniCode(miniId+"");
            message.put(code,object);

        }

        String tagCommand = getTagCommand(statusCommond.getModAddr(), uNum);

        logger.debug("发送查询标签码：" + tagCommand);
        ctx.channel().writeAndFlush(Unpooled.copiedBuffer(MBUtil.stringToHex(tagCommand)));


    }

    private String getTagCommand(String modAddr, int uNum) {
        StringBuffer miniCode = new StringBuffer();

        //起始位
        miniCode.append("FEFE");

        //后续长度
        miniCode.append("000F");

        //命令码号
        miniCode.append("EA");

        //版本号
        miniCode.append("0202");

        //主机id
        miniCode.append("00000000");


        StringBuffer childCode = new StringBuffer();

        //模块地址
        childCode.append(String.format("%02x", Integer.parseInt(modAddr)));

        //功能码
        childCode.append("03");

        //寄存器起始地址
        childCode.append("0040");

        //寄存器个数
        childCode.append(String.format("%04x", uNum * 2));

        //校验码
        childCode.append(MBUtil.getCRC(childCode.toString()));

        miniCode.append(childCode);

        return miniCode.toString();
    }
    /**
     * 解析标签码
     *
     * @param ctx
     * @param body
     */
    private void parseTagCommand(ChannelHandlerContext ctx, String body) {
        TagCommond tagCommond = new TagCommond(body);

        int uNum = tagCommond.getUNum();

        String tag = tagCommond.getTag();


        for (int i = 1; i <= uNum; i++) {

            //U位码
            String code = tagCommond.getMiniId()
                    + tagCommond.getModAddr()
                    + String.format("%02d", i);

            String tagCode = tag.substring((i - 1) * 8, i * 8);


            UObject object = message.get(code);

            if (object!=null){

                object.setTag(tagCode);
            }

        }



        Collection<UObject> list = message.values();


        String result = JSONObject.toJSONString(list);
        logger.debug("发送信息:"+result);
        //向前端传递告警信息
        for (Channel channel : ChannelPool.channelGroup) {

            channel.writeAndFlush(new TextWebSocketFrame(result));
        }
        message.clear();

    }


}
